/**************************************************************************//**
 * @file     FlashPrg.c
 * @brief    Flash Programming Functions adapted for New Device Flash
 * @version  V1.0.0
 * @date     10. January 2018
 ******************************************************************************/
/*
 * Copyright (c) 2010-2018 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include "FlashOS.H"        // FlashOS Structures

#include "fsl_common.h"
#include "fsl_gpio.h"
#include "fsl_iocon.h"
#include "fsl_swm.h"
#include "fsl_usart.h"
#include "drv_w25qxx.h"

/* 
   Mandatory Flash Programming Functions (Called by FlashOS):
                int Init        (unsigned long adr,   // Initialize Flash
                                 unsigned long clk,
                                 unsigned long fnc);
                int UnInit      (unsigned long fnc);  // De-initialize Flash
                int EraseSector (unsigned long adr);  // Erase Sector Function
                int ProgramPage (unsigned long adr,   // Program Page Function
                                 unsigned long sz,
                                 unsigned char *buf);

   Optional  Flash Programming Functions (Called by FlashOS):
                int BlankCheck  (unsigned long adr,   // Blank Check
                                 unsigned long sz,
                                 unsigned char pat);
                int EraseChip   (void);               // Erase complete Device
      unsigned long Verify      (unsigned long adr,   // Verify Function
                                 unsigned long sz,
                                 unsigned char *buf);

       - BlanckCheck  is necessary if Flash space is not mapped into CPU memory space
       - Verify       is necessary if Flash space is not mapped into CPU memory space
       - if EraseChip is not provided than EraseSector for all sectors is called
*/


/*
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Device Base Address
 *                    clk:  Clock Frequency (Hz)
 *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */
#define IOCON_PIO_CLKDIV0       0x00u       /*!<@brief IOCONCLKDIV0 */
#define IOCON_PIO_HYS_EN        0x20u       /*!<@brief Enable hysteresis */
#define IOCON_PIO_I2CMODE_FAST  0x00u       /*!<@brief Standard/Fast mode */
#define IOCON_PIO_INV_DI        0x00u       /*!<@brief Input not invert */
#define IOCON_PIO_MODE_PULLUP   0x10u       /*!<@brief Selects pull-up function */
#define IOCON_PIO_OD_DI         0x00u       /*!<@brief Disables Open-drain function */
#define IOCON_PIO_SMODE_BYPASS  0x00u       /*!<@brief Bypass input filter */

void usart_send_str(char *s,int len)
{
    for(int i=0;i<len;i++){
        while (0U == (USART0->STAT & USART_STAT_TXRDY_MASK))   {; }
        USART0->TXDAT = *s++;
    }
}

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {

    /* Add your Code */
    extern void BOARD_BootClockFRO30M(void);
    BOARD_BootClockFRO30M();
    W25QXX_Init();
    
    gpio_pin_config_t LED_config = {
        .pinDirection = kGPIO_DigitalOutput,
        .outputLogic = 1U,
    };
    GPIO_PinInit(GPIO, 0, 0, &LED_config);
    const uint32_t LED_RED = (/* Selects pull-up function */
                              IOCON_PIO_MODE_PULLUP |
                              /* Enable hysteresis */
                              IOCON_PIO_HYS_EN |
                              /* Input not invert */
                              IOCON_PIO_INV_DI |
                              /* Disables Open-drain function */
                              IOCON_PIO_OD_DI |
                              /* Bypass input filter */
                              IOCON_PIO_SMODE_BYPASS |
                              /* IOCONCLKDIV0 */
                              IOCON_PIO_CLKDIV0);
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_0, LED_RED);
    GPIO->CLR[0] = (1u << 0);


    /* Enables clock for switch matrix.: enable */
    CLOCK_EnableClock(kCLOCK_Swm);
    const uint32_t DEBUG_UART_RX = (/* Selects pull-up function */
                                    IOCON_PIO_MODE_PULLUP |
                                    /* Enable hysteresis */
                                    IOCON_PIO_HYS_EN |
                                    /* Input not invert */
                                    IOCON_PIO_INV_DI |
                                    /* Disables Open-drain function */
                                    IOCON_PIO_OD_DI |
                                    /* Bypass input filter */
                                    IOCON_PIO_SMODE_BYPASS |
                                    /* IOCONCLKDIV0 */
                                    IOCON_PIO_CLKDIV0);
    /* PIO1 PIN16 (coords: 36) is configured as USART0, RXD. */
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_24, DEBUG_UART_RX);

    const uint32_t DEBUG_UART_TX = (/* Selects pull-up function */
                                    IOCON_PIO_MODE_PULLUP |
                                    /* Enable hysteresis */
                                    IOCON_PIO_HYS_EN |
                                    /* Input not invert */
                                    IOCON_PIO_INV_DI |
                                    /* Disables Open-drain function */
                                    IOCON_PIO_OD_DI |
                                    /* Bypass input filter */
                                    IOCON_PIO_SMODE_BYPASS |
                                    /* IOCONCLKDIV0 */
                                    IOCON_PIO_CLKDIV0);
    /* PIO1 PIN17 (coords: 37) is configured as USART0, TXD. */
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_25, DEBUG_UART_TX);
    /* USART0_TXD connect to P0_25 */
    SWM_SetMovablePinSelect(SWM0, kSWM_USART0_TXD, kSWM_PortPin_P0_25);
    /* USART0_RXD connect to P0_24 */
    SWM_SetMovablePinSelect(SWM0, kSWM_USART0_RXD, kSWM_PortPin_P0_24);
    /* Disable clock for switch matrix. */
    CLOCK_DisableClock(kCLOCK_Swm);
    
    CLOCK_EnableClock(kCLOCK_Uart0);
    CLOCK_Select(kUART0_Clk_From_MainClk);
    RESET_PeripheralReset(kUART0_RST_N_SHIFT_RSTn);
    USART0->CFG = 0x05;
    USART0->BRG = 0x13;
    USART0->OSR = 0x0c;
    
    USART0->TXDAT = 0xaa;
    return (0);                                  // Finished without Errors
}

/*
 *  De-Initialize Flash Programming Functions
 *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int UnInit (unsigned long fnc) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseChip (void) {

  /* Add your Code */
    USART0->TXDAT = 0x55;
    GPIO->SET[0] = (1u << 0);
    W25QXX_EraseChip();
    GPIO->CLR[0] = (1u << 0);
  return (0);                                  // Finished without Errors
}


/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseSector (unsigned long adr) {

  /* Add your Code */
//    usart_send_str((char *)adr,4);
    USART0->TXDAT = 0x5a;
    GPIO->SET[0] = (1u << 0);
    W25QXX_EraseSector(adr-0x30000000);
    GPIO->CLR[0] = (1u << 0);
  return (0);                                  // Finished without Errors
}


/*
 *  Program Page in Flash Memory
 *    Parameter:      adr:  Page Start Address
 *                    sz:   Page Size
 *                    buf:  Page Data
 *    Return Value:   0 - OK,  1 - Failed
 */

int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {

  /* Add your Code */
//    usart_send_str((char *)adr,4);
//    usart_send_str((char *)sz,4);
//    USART0->TXDAT = buf[0];
    GPIO->SET[0] = (1u << 0);
    W25QXX_Write_NoCheck(adr-0x30000000,buf,sz);
    GPIO->CLR[0] = (1u << 0);
  return (0);                                  // Finished without Errors
}


unsigned long Verify      ( unsigned long adr,   // Verify Function
                            unsigned long sz,
                            unsigned char *buf)
{
    unsigned long i=0;
    unsigned char buff[16];
    USART0->TXDAT = buf[0];
    while(i<sz)
    {
        W25QXX_Read(adr-0x30000000 + i,buff, 16);
        for(int j=0;j<16;j++)
        {
            if(buff[j] != buf[i+j])
            {
                return adr+i+j;
            }
        }        
        i+=16;
    }
  return (adr+sz);
}

int  BlankCheck  (unsigned long adr,   // Blank Check
                    unsigned long sz,
                    unsigned char pat)
{
    USART0->TXDAT = 0x5f;
  return (0);
}







